package com.xquant.trade.risk.controller;

import  cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.xquant.common.core.utils.StringUtils;
import com.xquant.common.engine.xPP.cxf.NotifyDataFacade;
import com.xquant.common.engine.xPP.request.CalcEngineParam;
import com.xquant.common.engine.xPP.request.CalcPricingParam;
import com.xquant.common.engine.xPP.request.CalcSceneParam;
import com.xquant.common.engine.xPP.request.Instrument;
import com.xquant.common.engine.xPP.response.CalcScene;
import com.xquant.common.engine.xPP.response.Contract;
import com.xquant.common.log.annotation.Log;
import com.xquant.common.log.enums.BusinessType;
import com.xquant.common.security.annotation.RequiresPermissions;
import com.xquant.common.security.utils.ExcelUtil;
import com.xquant.common.security.utils.SecurityUtils;
import com.xquant.trade.utils.ResponseVo;
import com.xquant.trade.risk.entity.SceneResponse;
import com.xquant.trade.risk.entity.SceneThread;
import com.xquant.trade.risk.service.RiskService;
import com.xquant.trade.trade.entity.Trade;
import com.xquant.trade.utils.*;
import org.apache.commons.collections.MapUtils;
import org.apache.poi.hssf.usermodel.HSSFDataFormat;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.NonNull;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * @author ershuai.zhao
 */
@RestController
@RequestMapping("scene")
public class SceneRiskController {
    @Autowired
    private RiskService riskService;
    @Autowired
    private NotifyDataFacade notifyDataFacade;
    private static final Logger logger = LoggerFactory.getLogger(SceneRiskController.class);

    //IO线程工厂类
    static ThreadFactory threadFactory = new ThreadFactory() {
        @Override
        public Thread newThread(@NonNull Runnable runnable) {
            Thread thread = new Thread(runnable);
            thread.setName("calcTpAll-pool-");
            return thread;
        }
    };
    private static ThreadPoolExecutor executors = new ThreadPoolExecutor(10,
            20,
            60,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<Runnable>(Integer.MAX_VALUE), threadFactory, new ThreadPoolExecutor.DiscardPolicy());

    /**
     * 账户情景分析
     */
    @RequestMapping(value = "/calcAccountScene.action")
    @RequiresPermissions(value = {"risk:fundmanage:fundanalysis:calc", "risk:profitmanage:profitanalysis:calc"})
    public CommResponse calcAccountScene(@RequestBody Map<String, Object> param) throws InterruptedException, ExecutionException {
        //1、通知行情变化
        notifyDataFacade.notifyDailySet();
        CacheUtil.getInstance().removeAllCacheData();
        //3、查询计算日期 交易日
        // P013XEQ-1801 账户/组合监控和情景分析增加计算日期，过滤已过期交易 botao.yu
        if (StringUtils.isNotNull(MapUtil.getStr(param, "dealDate"))) {
            param.put("calendarDate", MapUtil.getStr(param, "dealDate"));
        } else {
            param.put("calendarDate", riskService.getBlcDate());
        }

        CalcEngineParam calcEngineParam = new CalcEngineParam();
        //2、组装情景因子
        List<CalcSceneParam> calcSceneParamList = JSONUtil.toList(JSONUtil.parseArray(param.get("calcSceneParams").toString()), CalcSceneParam.class);
        calcEngineParam.setCalcSceneParams(calcSceneParamList);
        CalcPricingParam calcPricingParam = new CalcPricingParam();
        // 盘中管理，不处理计算日  xpp
        String blcDate = MapUtil.getStr(param, "dealDate");
        calcPricingParam.setValueDate(blcDate);
        calcPricingParam.setCfgId(SysUtils.toString(param.get("cfgId")));
        calcEngineParam.setCalcPricingParam(calcPricingParam);
        param.put("userId", SecurityUtils.getUserId());
        //查询合约明细
        if (SysUtils.isNotVoid(MapUtil.getStr(param, "groupId"))) {
            param.put("groupId", MapUtil.getStr(param, "groupId").split(","));
        }
        if (StrUtil.isNotBlank(MapUtils.getString(param, "accIds"))) {
            if (JSONUtil.parseArray(MapUtils.getString(param, "accIds")).size() > 0) {
                param.put("accIds", JSONUtil.parseArray(MapUtils.getString(param, "accIds")).toArray(String.class));
            }else {
                param.put("accIds", null);
            }
        }
        String[] tradeTypes = new String[]{"OtcOptionSell", "OtcOptionBuy"};
        param.put("tradeTypes", tradeTypes);
        param.put("userId", SecurityUtils.getUserId());
        //按界面传入的日期查询后再用实际交易日计算
        param.put("blcDate", param.get("calendarDate")); //筛选交易到期日筛选
        param.put("calcDate", param.get("calendarDate")); //筛选计算持仓数据的日期
        List<Trade> tradeList = riskService.queryMonitor4TradeList(param);
        param.put("blcDate", blcDate);
        // <挂钩标的+情景编号，<汇总指标+交易指标明细>>
        Map<String, Map> ret = new HashMap();
        // 标的列表
        List<String> uCodes = new ArrayList<>();
        Set<String> uCodesets = new HashSet<String>();
        List<Map> failList = new ArrayList();
        String a = DateUtil.now();
        if (tradeList.size() > 0) {
            List<Callable<SceneResponse>> tasks = new ArrayList<Callable<SceneResponse>>();//添加任务

            for (Trade trade :  tradeList) {
                Map failMap = new HashMap();
                if (!trade.getaType().equals("CTM")) {
                    continue;
                }
                Instrument instrument = JSON.parseObject(MapUtils.getString(trade.getInstrumentInfo(), "pCalc"), Instrument.class);
                if (ObjectUtil.isNull(instrument) || ObjectUtil.isNull(instrument.getTermsheet())) {
                    break;
                }
                //拷贝新对象
                CalcEngineParam calcEngineParamSon = new CalcEngineParam();
                BeanUtils.copyProperties(calcEngineParam, calcEngineParamSon);
                calcEngineParamSon.setInstrument(instrument);

                //标的
                String uCode = instrument.getTermsheet().getJSONArray("underlyerIds").get(0).toString();

                logger.info(StrUtil.format("I_CODE:{},calcEngineParam:{}", trade.getiCode(), JSONUtil.toJsonStr(calcEngineParamSon)));
                try {
                    //Callable<SceneResponse> qfe = new SceneThread(calcEngineService, calcEngineParamSon, trade, uCode);
                    //tasks.add(qfe);
                } catch (Exception ex) {
                    failMap.put("iCode", trade.getiCode());
                    failMap.put("uCode", uCode);
                    failMap.put("errInfo", ex.getMessage());
                    failList.add(failMap);
                    ex.printStackTrace();
                }
            }
            List<SceneResponse> retItemList = new ArrayList<>();
            // 将计算结果添加到 list 可以让线程阻塞
            List<Future<SceneResponse>> futures = executors.invokeAll(tasks);
            if (futures != null && futures.size() > 0) {
                for (Future<SceneResponse> future : futures) {
                    SceneResponse sRes = future.get();
                    ResponseVo retItem = sRes.getResponseVo();
                    Trade trade = sRes.getTrade();
                    String uCode = sRes.getuCode();
                    Map failMap = new HashMap();
                    logger.info("计算结果:" + JSONUtil.parseObj(retItem));
                    if (retItem.getResult() == null) {
                        failMap.put("iCode", trade.getiCode());
                        failMap.put("uCode", uCode);
                        failMap.put("errInfo", "计算结果为空，请检查条款！");
                        failList.add(failMap);
                        continue;
                    }
                    if (retItem.getErrorCode() > 0) {
                        failMap.put("iCode", trade.getiCode());
                        failMap.put("uCode", uCode);
                        failMap.put("errInfo", retItem.getErrorMsg());
                        failList.add(failMap);
                        continue;
                    }

                    List<CalcScene> calcScene = (List<CalcScene>) retItem.getResult();
                    for (int K = 0; K < calcScene.size(); K++) {
                        CalcScene scene = calcScene.get(K);
                        Contract contract = scene.getContract();
                        BigDecimal spotPrice = new BigDecimal(contract.getSpotPrice());
                        String sceneID = calcScene.get(K).getSceneID();
                        String key = uCode + "#" + sceneID;
                        uCodesets.add(uCode);

                        if (!ret.containsKey(key)) {
                            Map initItem = new HashMap();
                            initItem.put("uName", trade.getuIName());
                            initItem.put("uCode", uCode);
                            initItem.put("sceneID", sceneID);
                            initItem.put("uICode", uCode.split(",")[0]);
                            initItem.put("npv", BigDecimal.ZERO);
                            initItem.put("delta", BigDecimal.ZERO);
                            initItem.put("deltaCash", BigDecimal.ZERO);
                            initItem.put("gamma", BigDecimal.ZERO);
                            initItem.put("gammaCash", BigDecimal.ZERO);
                            initItem.put("vega", BigDecimal.ZERO);
                            initItem.put("rho", BigDecimal.ZERO);
                            initItem.put("theta", BigDecimal.ZERO);
                            initItem.put("calcPrice", contract.getSpotPrice());
                            initItem.put("details", new ArrayList<>());
                            ret.put(key, initItem);
                        }
                        boolean dwh = false;
                        BigDecimal npv = BigDecimal.ZERO;
                        BigDecimal delta = BigDecimal.ZERO;
                        BigDecimal deltaCash = BigDecimal.ZERO;
                        BigDecimal gamma = BigDecimal.ZERO;
                        BigDecimal gammaCash = BigDecimal.ZERO;
                        BigDecimal vega = BigDecimal.ZERO;
                        BigDecimal rho = BigDecimal.ZERO;
                        BigDecimal theta = BigDecimal.ZERO;
                        if (dwh) {
                            npv = new BigDecimal(contract.getNpv()).multiply(trade.getVolume()).setScale(4, BigDecimal.ROUND_UP);
                            delta = new BigDecimal(contract.getDelta()).multiply(trade.getVolume()).setScale(4, BigDecimal.ROUND_UP);
                            deltaCash = new BigDecimal(contract.getDelta()).multiply(trade.getVolume()).multiply(spotPrice).setScale(4, BigDecimal.ROUND_UP);

                            gamma = new BigDecimal(contract.getGamma()).multiply(trade.getVolume()).setScale(4, BigDecimal.ROUND_UP);
                            gammaCash = new BigDecimal(contract.getGamma()).multiply(trade.getVolume()).multiply(spotPrice.multiply(spotPrice)).divide(new BigDecimal(100)).setScale(4, BigDecimal.ROUND_UP);

                            vega = new BigDecimal(contract.getVega()).multiply(trade.getVolume()).setScale(4, BigDecimal.ROUND_UP);
                            rho = new BigDecimal(contract.getRho()).multiply(trade.getVolume()).setScale(4, BigDecimal.ROUND_UP);
                            theta = new BigDecimal(contract.getTheta()).multiply(trade.getVolume()).setScale(4, BigDecimal.ROUND_UP);

                        } else {
                            npv = new BigDecimal(contract.getNpv()).setScale(4, BigDecimal.ROUND_UP);
                            delta = new BigDecimal(contract.getDelta()).setScale(4, BigDecimal.ROUND_UP);
                            deltaCash = new BigDecimal(contract.getDelta()).multiply(spotPrice).setScale(4, BigDecimal.ROUND_UP);

                            // monitorDetail.setCashDelta(Double.parseDouble(contract.getDelta()) * Double.parseDouble(contract.getSpotPrice()));
                            // monitorDetail.setCashGamma(Double.parseDouble(contract.getGamma()) * Double.parseDouble(contract.getSpotPrice()) * Double.parseDouble(contract.getSpotPrice()) / 100);

                            gamma = new BigDecimal(contract.getGamma()).setScale(4, BigDecimal.ROUND_UP);
                            gammaCash = new BigDecimal(contract.getGamma()).multiply(spotPrice.multiply(spotPrice)).divide(new BigDecimal(100)).setScale(4, BigDecimal.ROUND_UP);

                            vega = new BigDecimal(contract.getVega()).setScale(4, BigDecimal.ROUND_UP);
                            rho = new BigDecimal(contract.getRho()).setScale(4, BigDecimal.ROUND_UP);
                            theta = new BigDecimal(contract.getTheta()).setScale(4, BigDecimal.ROUND_UP);
                        }
                        Map item = new HashMap();
                        item.put("iCode", trade.getiCode());
                        item.put("aType", trade.getaType());
                        item.put("mType", trade.getmType());
                        item.put("npv", npv);
                        item.put("delta", delta);
                        item.put("deltaCash", deltaCash);
                        item.put("gamma", gamma);
                        item.put("gammaCash", gammaCash);
                        item.put("vega", vega);
                        item.put("rho", rho);
                        item.put("theta", theta);
                        item.put("calcPrice", contract.getSpotPrice());
                        ret.get(key).put("npv", npv.add((BigDecimal) (ret.get(key).get("npv"))));
                        ret.get(key).put("delta", delta.add((BigDecimal) (ret.get(key).get("delta"))));
                        ret.get(key).put("deltaCash", deltaCash.add((BigDecimal) (ret.get(key).get("deltaCash"))));
                        ret.get(key).put("gamma", gamma.add((BigDecimal) (ret.get(key).get("gamma"))));
                        ret.get(key).put("gammaCash", gammaCash.add((BigDecimal) (ret.get(key).get("gammaCash"))));
                        ret.get(key).put("vega", vega.add((BigDecimal) (ret.get(key).get("vega"))));
                        ret.get(key).put("rho", rho.add((BigDecimal) (ret.get(key).get("rho"))));
                        ret.get(key).put("theta", theta.add((BigDecimal) (ret.get(key).get("theta"))));
                        for (int j = 0; j < calcSceneParamList.size(); j++) {
                            CalcSceneParam calcSceneParam = calcSceneParamList.get(j);
                            if (StrUtil.equals(calcSceneParam.getSceneID(), sceneID)) {
                                ret.get(key).put("volSurfaceInc", calcSceneParam.getUnderlyingSceneParams().get(0).getVolSurfaceInc() == null ? '1' : calcSceneParam.getUnderlyingSceneParams().get(0).getVolSurfaceInc());
                                ret.get(key).put("volSurfaceValInc", calcSceneParam.getUnderlyingSceneParams().get(0).getVolSurfaceInc() == null ? '0' : calcSceneParam.getUnderlyingSceneParams().get(0).getVolSurfaceInc().getValue());
                                ret.get(key).put("spotPriceInc", calcSceneParam.getUnderlyingSceneParams().get(0).getSpotPriceInc() == null ? '1' : calcSceneParam.getUnderlyingSceneParams().get(0).getSpotPriceInc());
                                ret.get(key).put("spotPriceValInc", calcSceneParam.getUnderlyingSceneParams().get(0).getSpotPriceInc() == null ? '0' : calcSceneParam.getUnderlyingSceneParams().get(0).getSpotPriceInc().getValue());
                            }
                        }
                        //8个联合主键
                        ret.get(key).put("iCode", trade.getiCode());
                        ret.get(key).put("aType", trade.getaType());
                        ret.get(key).put("mType", trade.getmType());
                        ret.get(key).put("accId", trade.getAccId());
                        ret.get(key).put("dimAccExt", trade.getDimExtAccId());
                        ret.get(key).put("dimLs", trade.getDimLs());
                        ret.get(key).put("currency", trade.getCurrency());
                        ret.get(key).put("dimSeq", trade.getDimGuid());

                        ((ArrayList) ret.get(key).get("details")).add(item);
                    }
                }
            }
        }
        String b = DateUtil.now();
        //处理计算结果
        Map<String, Map> resResult = new HashMap();
        Map<String, Map> realResult = new HashMap();
        uCodes.addAll(uCodesets);
        for (int i = 0; i < uCodes.size(); i++) {
            for (Map.Entry<String, Map> entry : ret.entrySet()) {

                if (StrUtil.equals(entry.getKey().split("#")[0], uCodes.get(i))) {
                    Map valMap = entry.getValue();
                    String key = MapUtil.getStr(valMap, "uCode") + "#" + MapUtil.getStr(valMap, "volSurfaceValInc");
                    String spotPriceValInc = MapUtil.getStr(valMap, "spotPriceValInc");
                    String spotPriceValIncN = spotPriceValInc.replace(".", "_");
                    String volSurfaceValInc = MapUtil.getStr(valMap, "volSurfaceValInc");
                    String volSurfaceValIncN = volSurfaceValInc.replace(".", "_");
                    String calcPrice = MapUtil.getStr(valMap, "calcPrice");
                    String calcPriceN = calcPrice.replace(".", "_");
                    if (!resResult.containsKey(key)) {
                        Map initItem = new HashMap();
                        initItem.put("uName", MapUtil.getStr(valMap, "uName"));
                        initItem.put("uCode", MapUtil.getStr(valMap, "uCode"));
                        initItem.put("uICode", MapUtil.getStr(valMap, "uCode").split(",")[0]);
                        initItem.put("volSurfaceValInc", volSurfaceValInc);
                        initItem.put("spotPriceValInc#" + spotPriceValIncN, spotPriceValInc);
                        initItem.put("calcPrice#" + calcPriceN, calcPrice);
                        resResult.put(key, initItem);
                    }
                    Map map = resResult.get(key);

                    map.put("spotPriceValInc#" + calcPriceN + "#" + spotPriceValIncN + "#npv", MapUtil.getDouble(valMap, "npv"));
                    map.put("spotPriceValInc#" + calcPriceN + "#" + spotPriceValIncN + "#delta", MapUtil.getDouble(valMap, "delta"));
                    map.put("spotPriceValInc#" + calcPriceN + "#" + spotPriceValIncN + "#deltaCash", MapUtil.getDouble(valMap, "deltaCash"));
                    map.put("spotPriceValInc#" + calcPriceN + "#" + spotPriceValIncN + "#gamma", MapUtil.getDouble(valMap, "gamma"));
                    map.put("spotPriceValInc#" + calcPriceN + "#" + spotPriceValIncN + "#gammaCash", MapUtil.getDouble(valMap, "gammaCash"));
                    map.put("spotPriceValInc#" + calcPriceN + "#" + spotPriceValIncN + "#theta", MapUtil.getDouble(valMap, "theta"));
                    map.put("spotPriceValInc#" + calcPriceN + "#" + spotPriceValIncN + "#vega", MapUtil.getDouble(valMap, "vega"));
                    map.put("spotPriceValInc#" + calcPriceN + "#" + spotPriceValIncN + "#rho", MapUtil.getDouble(valMap, "rho"));
                    map.put("calcPrice#" + calcPriceN, calcPrice);

                }
            }
            realResult.put(uCodes.get(i), resResult);
        }
        //map 转List
        List<Map> successList = new ArrayList();
        for (int i = 0; i < uCodes.size(); i++) {
            Map map = realResult.get(uCodes.get(i));
            List<Map> sonList = new ArrayList(map.values());
            successList.addAll(sonList);
        }

        // 获取动态 fields
        Set<String> fieldSets = new HashSet<String>();
        if (successList.size() > 0) {
            fieldSets = successList.get(0).keySet();
        }
        sortSet = new TreeSet<>();
        sortSet.addAll(fieldSets);

        HashMap<String, Object> result = new HashMap<>();
        //进行升序排列
        successList = successList.stream()
                .sorted(Comparator.comparing(
                        h -> (Float.parseFloat(h.get("volSurfaceValInc").toString()))))
                .collect(Collectors.toList());
        result.put("success", successList);
        result.put("error", failList);
        result.put("fields", sortSet);
        return new CommResponse(true, result);
    }


    /**
     * 20221102 botao.yu 增加情景分析结果导出功能
     */
    @Log(title = "情景分析导出", businessType = BusinessType.EXPORT,isSaveRequestData=false)
    @RequiresPermissions(value = {"risk:fundmanage:fundanalysis:export", "risk:profitmanage:profitanalysis:export"})
    @RequestMapping(value = "/export")
    public void export(HttpServletResponse response, @RequestParam Map<String, Object> param) {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        JSONArray calcResult= JSON.parseArray(param.get("calcResult").toString());
        JSONArray errResult=JSON.parseArray(param.get("errResult").toString());
        String  calcTitle=param.get("calcTitle").toString();
        JSONObject field= JSON.parseObject(param.get("field").toString(), JSONObject.class);
        Workbook wb=new SXSSFWorkbook(500);
        Map<String, CellStyle> styles =ExcelUtil.createStyles(wb);
        try
        {
            //绘制Excel格式 填充Excel数据
            for(String key:field.keySet()){
                //新建sheet页
                Sheet sheet=wb.createSheet(key);
                //新建sheet页title
                Row titleRow = sheet.createRow(0);
                titleRow.setHeightInPoints(30);
                Cell titleCell = titleRow.createCell(0);
                titleCell.setCellStyle(styles.get("title"));
                titleCell.setCellValue(key);
                //列数量
                JSONArray fieldArray=field.getJSONArray(key);
                sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), titleRow.getRowNum(),
                        fieldArray.size() - 1+4));
                Map<Integer,Double> colSumMap=new HashMap<>();
                //填充数据，包含header头信息
                for(int j=1;j<calcResult.size()+2;j++) {
                    //新建行 j=1时为header >1时为数据行
                    Row dataRow = sheet.createRow(j);
                    JSONObject resultData=new JSONObject();
                    if(j>1){
                       resultData= (JSONObject) calcResult.get(j-2);
                    }
                    //新建首行cell元素
                    Cell serialCell = dataRow.createCell(0);
                    CellStyle cellStyle=j==1?styles.get("header"):styles.get("data2");
                    // 写入序号列信息
                    serialCell.setCellValue(j==1?"序号":String.valueOf(j-1));
                    sheet.setColumnWidth(0, (int) ((16 + 0.72) * 256));
                    serialCell.setCellStyle(cellStyle);
                    // 写入标的代码列信息
                    Cell iCodeCell = dataRow.createCell(1);
                    iCodeCell.setCellValue(j>1?resultData.getString("uICode"):"标的代码");
                    sheet.setColumnWidth(1, (int) ((16 + 0.72) * 256));
                    iCodeCell.setCellStyle(cellStyle);
                    // 写入标的代码列信息
                    Cell iNameCell = dataRow.createCell(2);
                    iNameCell.setCellValue(j>1?resultData.getString("uName"):"标的名称");
                    sheet.setColumnWidth(2, (int) ((16 + 0.72) * 256));
                    iNameCell.setCellStyle(cellStyle);
                    // 写入标的代码列信息
                    Cell volTypeCell = dataRow.createCell(3);
                    volTypeCell.setCellValue(j>1? NumberUtil.add(1,resultData.getDoubleValue("volSurfaceValInc"))*100+"%" :calcTitle);
                    sheet.setColumnWidth(3, (int) ((24 + 0.72) * 256));
                    volTypeCell.setCellStyle(cellStyle);
                    int i = 4;
                    CellStyle cs = wb.createCellStyle();
                    for (Object fieldObj : fieldArray) {
                        Cell fieldCell = dataRow.createCell(i);
                        if(j>1){
                            double cv=resultData.getDoubleValue(((JSONObject) fieldObj).getString("valueId"));
                            fieldCell.setCellValue(NumberUtil.round(cv,2).doubleValue());
                            colSumMap.put(i,NumberUtil.round(MapUtils.getDouble(colSumMap,i,0d)+cv,2).doubleValue());
                        }else{
                            fieldCell.setCellValue(((JSONObject) fieldObj).getString(("text").replaceAll(",","")));
                        }
                        sheet.setColumnWidth(i, (int) ((22 + 0.72) * 256));
                        fieldCell.setCellStyle(cellStyle);
                        cs.cloneStyleFrom(fieldCell.getCellStyle());
                        cs.setDataFormat(HSSFDataFormat.getBuiltinFormat("#,##0.00"));
                        cs.setAlignment(HorizontalAlignment.RIGHT);
                        fieldCell.setCellStyle(cs);
                        i++;
                    }
                }
                //增加均值行 字体为红色
                Font font = wb.createFont();
                font.setColor(IndexedColors.RED.getIndex());
                CellStyle cs = wb.createCellStyle();
                cs.cloneStyleFrom(styles.get("data2"));
                cs.setAlignment(HorizontalAlignment.CENTER);
                cs.setFont(font);
                Row sumRow = sheet.createRow(calcResult.size()+2);
                Cell sumTitleCell = sumRow.createCell(3);
                sumTitleCell.setCellStyle(cs);
                sumTitleCell.setCellValue("风险均值");
                //合计数据遍历
                for(Integer colIndex:colSumMap.keySet()){
                    Cell sumDataCell=sumRow.createCell(colIndex);
                    CellStyle cs2 = wb.createCellStyle();
                    cs2.cloneStyleFrom(styles.get("data2"));
                    cs2.setDataFormat(HSSFDataFormat.getBuiltinFormat("#,##0.00"));
                    cs2.setAlignment(HorizontalAlignment.RIGHT);
                    cs2.setFont(font);
                    sumDataCell.setCellStyle(cs2);
                    sumDataCell.setCellValue(NumberUtil.round(colSumMap.get(colIndex).doubleValue()/(calcResult.size()==0?1:calcResult.size()),2).doubleValue());
                }
            }
            //增加异常sheet
            if(errResult!=null&&errResult.size()>0){
                //增加表头大标题
                Sheet sheet=wb.createSheet("异常信息");
                Row titleRow = sheet.createRow(0);
                titleRow.setHeightInPoints(30);
                Cell titleCell = titleRow.createCell(0);
                titleCell.setCellStyle(styles.get("title"));
                titleCell.setCellValue("异常信息");
                sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), titleRow.getRowNum(),
                        3 - 1));
                //遍历异常信息
                for(int j=1;j<errResult.size()+2;j++) {
                    //新建行 j=1时为header >1时为数据行
                    Row dataRow = sheet.createRow(j);
                    JSONObject resultData = new JSONObject();
                    if (j > 1) {
                        resultData = (JSONObject) errResult.get(j - 2);
                    }
                    //新建首行cell元素
                    Cell serialCell = dataRow.createCell(0);
                    CellStyle cellStyle = j == 1 ? styles.get("header") : styles.get("data2");
                    // 写入序号列信息
                    serialCell.setCellValue(j == 1 ? "序号" : String.valueOf(j - 1));
                    sheet.setColumnWidth(0, (int) ((16 + 0.72) * 256));
                    serialCell.setCellStyle(cellStyle);
                    // 写入合约编号信息
                    Cell iCodeCell = dataRow.createCell(1);
                    iCodeCell.setCellValue(j>1?resultData.getString("iCode"):"合约编号");
                    sheet.setColumnWidth(1, (int) ((16 + 0.72) * 256));
                    iCodeCell.setCellStyle(cellStyle);
                    // 写入异常明细信息
                    Cell errInfoCell = dataRow.createCell(2);
                    errInfoCell.setCellValue(j>1?resultData.getString("errInfo"):"异常信息");
                    sheet.setColumnWidth(2, (int) ((30 + 0.72) * 256));
                    errInfoCell.setCellStyle(cellStyle);
                }
            }
            wb.write(response.getOutputStream());
        }
        catch (Exception e)
        {
            logger.error("导出Excel异常{}", e.getMessage());
        }
        finally
        {
            IOUtils.closeQuietly(wb);
        }
    }


    /**
     *
     */
    @RequestMapping(value = "/getICodePrice.action")
    public CommResponse getICodePrice(@RequestParam Map<String, Object> param) {
        List<Map> list = riskService.getICodePrice(param);
        return new CommResponse(true, list);
    }

    /**
     *
     */
    @RequestMapping(value = "/getICodeInfo.action")
    public CommResponse getICodeInfo(@RequestParam Map<String, Object> param) {
        List<Map> list = riskService.getICodePrice(param);
        return new CommResponse(true, list);
    }

    Set<String> sortSet = new TreeSet<String>(new Comparator<String>() {
        @Override
        public int compare(String o1, String o2) {
            return o1.compareTo(o2);//降序排列
        }
    });
}
